package cn.redragon.soa.common.util;

import java.nio.charset.StandardCharsets;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import javax.crypto.Cipher;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;

/**
 * @Author: Steven HUANG
 * @Date: 2019/7/3
 */
@Slf4j
public class CryptUtil {

    private static final String AES_CBC_PCK_ALG = "AES/CBC/PKCS5Padding";

    private static final String AES_ALG = "AES";

    @SneakyThrows
    public static String encryptWithAes(String content, String encodingAesKey) {
        if (encodingAesKey == null) {
            return content;
        }
        return encryptWithAes(content, null, encodingAesKey);
    }

    @SneakyThrows
    public static String decryptWithAes(String contentEncrypted, String encodingAesKey) {
        if (encodingAesKey == null) {
            return contentEncrypted;
        }
        return decryptWithAes(contentEncrypted, null, encodingAesKey);
    }

    @SneakyThrows
    public static String encryptWithAes(String content, String iv, String encodingAesKey) {
        try {
            if (encodingAesKey == null) {
                return content;
            }
            Cipher cipher = getCipher(iv, encodingAesKey, Cipher.ENCRYPT_MODE);

            byte[] encryptBytes = cipher.doFinal(content.getBytes(StandardCharsets.UTF_8));
            return Base64.encodeBase64String(encryptBytes);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            throw new CryptException(CryptException.ENCRYPT_AES_ERROR);
        }
    }

    @SneakyThrows
    public static String decryptWithAes(String contentEncrypted, String iv, String encodingAesKey) {
        try {
            if (encodingAesKey == null) {
                return contentEncrypted;
            }
            Cipher cipher = getCipher(iv, encodingAesKey, Cipher.DECRYPT_MODE);
            byte[] cleanBytes = cipher.doFinal(Base64.decodeBase64(contentEncrypted.getBytes()));
            return new String(cleanBytes, StandardCharsets.UTF_8);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            throw new CryptException(CryptException.DECRYPT_AES_ERROR);
        }
    }

    public static String generateAesKey() {
        return Base64.encodeBase64String(RandomStringUtils.randomAlphanumeric(32).getBytes());
    }

    @SneakyThrows
    public static void main(String[] args) {
        System.out.println(generateAesKey());
        String encodingAesKey = "Smlpb1FMY3RPZGRCR2pZMnRqOTJnemxGYkRuSUdZaVU=";
        String content = "[{\"name\": \"test1\",\"address\":\"上海市田林路117号8n\"},{\"name\": \"test2\",\"name\":\"上海市田林路117号gg\"\"}]";

        String iv = Base64.encodeBase64String(RandomStringUtils.randomAlphanumeric(16).getBytes());
        System.out.println(encryptWithAes(content, iv, encodingAesKey));
    }

    private static Cipher getCipher(String iv, String encodingAesKey, int decryptMode) throws NoSuchAlgorithmException, NoSuchPaddingException,
        InvalidKeyException, InvalidAlgorithmParameterException {
        byte[] aesKey = Base64.decodeBase64(encodingAesKey);
        Cipher cipher = Cipher.getInstance(AES_CBC_PCK_ALG);
        IvParameterSpec ivPS;
        if (StringUtils.isNotBlank(iv)) {
            ivPS = new IvParameterSpec(Base64.decodeBase64(iv), 0, 16);
        } else {
            ivPS = new IvParameterSpec(aesKey, 0, 16);
        }
        cipher.init(decryptMode, new SecretKeySpec(aesKey, AES_ALG), ivPS);
        return cipher;
    }
}
